package top.goldenyear.porpoise.common.core.util.string;

import cn.hutool.v7.core.array.ArrayUtil;
import cn.hutool.v7.core.collection.CollUtil;
import cn.hutool.v7.core.convert.ConvertUtil;
import cn.hutool.v7.core.text.CharUtil;
import cn.hutool.v7.core.text.NamingCase;
import cn.hutool.v7.core.text.StrUtil;
import cn.hutool.v7.core.text.split.SplitUtil;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 字符串工具类
 *
 * @author Airhead
 */
public class StrUtils extends StrUtil {

  /**
   * 给定字符串是否以任何一个字符串开始 给定字符串和数组为空都返回 false
   *
   * @param str      给定字符串
   * @param prefixes 需要检测的开始字符串
   * @since 3.0.6
   */
  public static boolean startWithAny(String str, Collection<String> prefixes) {
    if (StrUtil.isEmpty(str) || ArrayUtil.isEmpty(prefixes)) {
      return false;
    }

    for (CharSequence suffix : prefixes) {
      if (StrUtil.startWith(str, suffix, false)) {
        return true;
      }
    }
    return false;
  }

  public static List<Long> splitToLong(String value, CharSequence separator) {
    List<String> list = SplitUtil.split(value, separator);
    return list.stream().map(ConvertUtil::toLong).collect(Collectors.toList());
  }

  /**
   * 移除字符串中，包含指定字符串的行
   *
   * @param content  字符串
   * @param sequence 包含的字符串
   * @return 移除后的字符串
   */
  public static String removeLineContains(String content, String sequence) {
    if (StrUtil.isEmpty(content) || StrUtil.isEmpty(sequence)) {
      return content;
    }
    return Arrays.stream(content.split("\n")).filter(line -> !line.contains(sequence)).collect(Collectors.joining("\n"));
  }

  /**
   * 第一个字符转换为小写
   *
   * @param string
   */
  public static String lowerFirst(String string) {
    return StrUtil.lowerFirst(string);
  }

  /**
   * 第一个字符转换为大写
   *
   * @param string
   */
  public static String upperFirst(String string) {
    return StrUtil.upperFirst(string);
  }

  /**
   * 驼峰转下划线格式
   *
   * @param string
   */
  public static String camelToUnderline(String string) {
    return StrUtil.toUnderlineCase(string);
  }

  /**
   * 驼峰转连字符格式
   *
   * @param string
   */
  public static String camelToKebab(String string) {
    return NamingCase.toKebabCase(string);
  }

  /**
   * 下划线转驼峰格式
   *
   * @param string
   */
  public static String underlineToCamel(String string) {
    return NamingCase.toCamelCase(string, CharUtil.UNDERLINE);
  }

  /**
   * 下划线转驼峰格式
   *
   * @param string
   */
  public static String underlineToKebab(String string) {
    String camelCase = StrUtil.toCamelCase(string, CharUtil.UNDERLINE);

    return NamingCase.toSymbolCase(camelCase, CharUtil.DASHED);
  }

  /**
   * 连字符转驼峰格式
   *
   * @param string
   */
  public static String kebabToCamel(String string) {
    return NamingCase.toCamelCase(string, CharUtil.DASHED);
  }

  /**
   * 字符串为 null 或者内部字符全部为 ' ', '\t', '\n', '\r' 这四类字符时返回 true
   */
  public static boolean isBlank(String str) {
    if (str == null) {
      return true;
    }

    for (int i = 0, len = str.length(); i < len; i++) {
      if (str.charAt(i) > ' ') {
        return false;
      }
    }
    return true;
  }

  public static boolean isAnyBlank(String... strings) {
    if (strings == null || strings.length == 0) {
      throw new IllegalArgumentException("args is empty.");
    }

    for (String str : strings) {
      if (isBlank(str)) {
        return true;
      }
    }
    return false;
  }

  public static boolean isNotBlank(String str) {
    return !isBlank(str);
  }

  public static boolean areNotBlank(String... strings) {
    return !isAnyBlank();
  }

  /**
   * 这个字符串是否是全是数字
   *
   * @param str
   * @return
   */
  public static boolean isNumeric(String str) {
    return StrUtil.isNumeric(str);
  }

  public static boolean startsWithAny(String str, String... prefixes) {
    return StrUtil.startWithAny(str, prefixes);
  }

  public static boolean endsWithAny(String str, String... suffixes) {
    return StrUtil.endWithAny(str, suffixes);
  }

  public static String trimOrNull(String string) {
    return string != null ? string.trim() : null;
  }

  /**
   * 正则匹配
   *
   * @param regex
   * @param input
   * @return
   */
  public static boolean matches(String regex, String input) {
    if (null == regex || null == input) {
      return false;
    }
    return Pattern.matches(regex, input);
  }

  /**
   * 合并字符串，优化 String.join() 方法
   *
   * @param delimiter
   * @param elements
   * @return 新拼接好的字符串
   * @see String#join(CharSequence, CharSequence...)
   */
  public static String join(String delimiter, CharSequence... elements) {
    if (ArrayUtil.isEmpty(elements)) {
      return "";
    } else if (elements.length == 1) {
      return String.valueOf(elements[0]);
    } else {
      return String.join(delimiter, elements);
    }
  }

  /**
   * 合并字符串，优化 String.join() 方法
   *
   * @param delimiter
   * @param elements
   * @return 新拼接好的字符串
   * @see String#join(CharSequence, CharSequence...)
   */
  public static String join(String delimiter, Collection<? extends CharSequence> elements) {
    if (CollUtil.isEmpty(elements)) {
      return "";
    } else if (elements.size() == 1) {
      return String.valueOf(elements.iterator().next());
    } else {
      return String.join(delimiter, elements);
    }
  }

  /**
   * 合并字符串，优化 String.join() 方法
   *
   * @param delimiter
   * @param objs
   * @param function
   * @param <T>
   */
  public static <T> String join(String delimiter, Collection<T> objs, Function<T, String> function) {
    if (CollUtil.isEmpty(objs)) {
      return "";
    } else if (objs.size() == 1) {
      T next = objs.iterator().next();
      return String.valueOf(function.apply(next));
    } else {
      String[] strings = new String[objs.size()];
      int index = 0;
      for (T obj : objs) {
        strings[index++] = function.apply(obj);
      }
      return String.join(delimiter, strings);
    }
  }

  public static String tryTrim(String string) {
    return string != null ? string.trim() : null;
  }
}
